-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[release-2.5.0] Fix missing operationName
in apollo-engine-reporting
.
#2557
[release-2.5.0] Fix missing operationName
in apollo-engine-reporting
.
#2557
Conversation
This should fail and then be fixed with an upcoming commit.
The full-query caching feature implemented in #2437 originally took the additional steps of also changing the `apollo-engine-reporting` module to utilize the new request pipeline available in Apollo Server as of #1795. While that would have been nice, there was still some uncertainty about some of the life-cycle hooks that would be necesssary to make that happen and it wasn't worth blocking the implementation of full-query caching on those stalled decisions. Therefore, the changes to utilize new functionality in the request pipeline, including what would have been a simplification of the way that `apollo-engine-reporting` would have obtained the `operationName` (something that is available via the API of the request-pipeline hooks), were backed out and will land separately in a future PR. The portion regarding `operationName` was inadvertently not backed out and instead was left leveraging a life-cycle hook which was not available to the `graphql-extensions` API: `didResolveOperation`. This means that the code was not setting `operationName` in the way it needed to and therefore `operationName` was always being left undefined (as is sometimes permitted!) with this new `apollo-engine-reporting`. This commit puts the functionality back to that which is required for the `graphql-extensions` implementation, and the commit before this (8a43341) acts as a regression test (it should pass, as of this commit, and fail before it).
Hmm. I actually think this is an inaccurate description of what happened in #2437. I'm moderately sure that I 100% intended to leave in the extension didResolveOperation API, and the mistake was just not invoking it in requestPipeline. The PR description there did describe the motivation: the desire to register the operation with the stack before doing responseForOperation (for the cache). I see that since then this has been addressed by making the "requestDidEnd" callback hang on to the requestContext passed in to This stuff is complex and I'm not upset that this got done while I was out, but I think it's worth at least recording my intentions for posterity. |
Actually I think you were right to back the change out for a reason that'll be described in a change I'm making. |
The full query caching change (#2437) intended to introduce didResolveOperation to the old graphql-extensions API used by apollo-engine-reporting ("backporting" it from the newer plugin API). However, that change accidentally forgot to invoke didResolveOperation from the request pipeline! This meant that the operation name never got reported. The change was backed out in #2557. But this unfortunately re-introduced the exact bug that the change in #2437 was intended to fix: operationName was no longer set when a result is served from the cache! Additionally, it was not set if a *plugin* didResolveOperation call threw, which is what happens when the operation registry plugin forbids an operation. While we could have fixed this by reintroducing the didResolveOperation extension API, there would be a subtle requirement that the apollo-engine-reporting extension didResolveOperation be run before the possibly-throwing operation registry didResolveOperation. So instead, @abernix implemented #2711. This used `requestContext.operationName` as a fallback if neither executionDidStart nor willResolveField gets called. This will be set if the operation properly parsed, validates, and either has a specified operationName that is found in the document, or there is no specified operationName and there is exactly one operation in the document and it has a name. (Note that no version of this code ever sent the user-provided operationName in case of parse or validation errors.) The existing code is correct, but this PR cleans up a few things: - #2557 reverted the one *implementation* of the didResolveOperation extension API, and #2437 accidentally didn't contain any *callers* of the API, but it was still declared on GraphQLExtension and GraphQLExtensionStack. This PR removes those declarations (which have never been useful). - We currently look for the operation name in willResolveField. But in any case where fields are successfully being resolved, the pipeline must have managed to successfully resolve the operation and set requestContext.operationName. So we don't actually need the willResolveField code, because the "fallback" in the requestDidStart end-callback will have the same value. So take this code away. (This change is the motivation for this PR; for federation metrics I'm trying to disengage the "calculate times for fields" part of trace generation from the rest of it.) - Fix the comment in "requestDidEnd" that implied incorrectly that requestContext.operationName was the user-provided name rather than the pipeline-calculated name. Be explicit both there and in requestPipeline.ts that we are relying on the fact that the RequestContext passed to requestDidStart is mutated to add operationName before its end handler is called. This change is intended to be a no-op change (other than the removal of the never-used APIs).
The full query caching change (#2437) intended to introduce didResolveOperation to the old graphql-extensions API used by apollo-engine-reporting ("backporting" it from the newer plugin API). However, that change accidentally forgot to invoke didResolveOperation from the request pipeline! This meant that the operation name never got reported. The change was backed out in #2557. But this unfortunately re-introduced the exact bug that the change in #2437 was intended to fix: operationName was no longer set when a result is served from the cache! Additionally, it was not set if a *plugin* didResolveOperation call threw, which is what happens when the operation registry plugin forbids an operation. While we could have fixed this by reintroducing the didResolveOperation extension API, there would be a subtle requirement that the apollo-engine-reporting extension didResolveOperation be run before the possibly-throwing operation registry didResolveOperation. So instead, @abernix implemented #2711. This used `requestContext.operationName` as a fallback if neither executionDidStart nor willResolveField gets called. This will be set if the operation properly parsed, validates, and either has a specified operationName that is found in the document, or there is no specified operationName and there is exactly one operation in the document and it has a name. (Note that no version of this code ever sent the user-provided operationName in case of parse or validation errors.) The existing code is correct, but this PR cleans up a few things: - #2557 reverted the one *implementation* of the didResolveOperation extension API, and #2437 accidentally didn't contain any *callers* of the API, but it was still declared on GraphQLExtension and GraphQLExtensionStack. This PR removes those declarations (which have never been useful). - We currently look for the operation name in willResolveField. But in any case where fields are successfully being resolved, the pipeline must have managed to successfully resolve the operation and set requestContext.operationName. So we don't actually need the willResolveField code, because the "fallback" in the requestDidStart end-callback will have the same value. So take this code away. (This change is the motivation for this PR; for federation metrics I'm trying to disengage the "calculate times for fields" part of trace generation from the rest of it.) - Fix the comment in "requestDidEnd" that implied incorrectly that requestContext.operationName was the user-provided name rather than the pipeline-calculated name. Be explicit both there and in requestPipeline.ts that we are relying on the fact that the RequestContext passed to requestDidStart is mutated to add operationName before its end handler is called. This change is intended to be a no-op change (other than the removal of the never-used APIs).
The full query caching change (#2437) intended to introduce didResolveOperation to the old graphql-extensions API used by apollo-engine-reporting ("backporting" it from the newer plugin API). However, that change accidentally forgot to invoke didResolveOperation from the request pipeline! This meant that the operation name never got reported. The change was backed out in #2557. But this unfortunately re-introduced the exact bug that the change in #2437 was intended to fix: operationName was no longer set when a result is served from the cache! Additionally, it was not set if a *plugin* didResolveOperation call threw, which is what happens when the operation registry plugin forbids an operation. While we could have fixed this by reintroducing the didResolveOperation extension API, there would be a subtle requirement that the apollo-engine-reporting extension didResolveOperation be run before the possibly-throwing operation registry didResolveOperation. So instead, @abernix implemented #2711. This used `requestContext.operationName` as a fallback if neither executionDidStart nor willResolveField gets called. This will be set if the operation properly parsed, validates, and either has a specified operationName that is found in the document, or there is no specified operationName and there is exactly one operation in the document and it has a name. (Note that no version of this code ever sent the user-provided operationName in case of parse or validation errors.) The existing code is correct, but this PR cleans up a few things: - #2557 reverted the one *implementation* of the didResolveOperation extension API, and #2437 accidentally didn't contain any *callers* of the API, but it was still declared on GraphQLExtension and GraphQLExtensionStack. This PR removes those declarations (which have never been useful). - We currently look for the operation name in willResolveField. But in any case where fields are successfully being resolved, the pipeline must have managed to successfully resolve the operation and set requestContext.operationName. So we don't actually need the willResolveField code, because the "fallback" in the requestDidStart end-callback will have the same value. So take this code away. (This change is the motivation for this PR; for federation metrics I'm trying to disengage the "calculate times for fields" part of trace generation from the rest of it.) - Fix the comment in "requestDidEnd" that implied incorrectly that requestContext.operationName was the user-provided name rather than the pipeline-calculated name. Be explicit both there and in requestPipeline.ts that we are relying on the fact that the RequestContext passed to requestDidStart is mutated to add operationName before its end handler is called. This change is intended to be a no-op change (other than the removal of the never-used APIs).
The full query caching change (#2437) intended to introduce didResolveOperation to the old graphql-extensions API used by apollo-engine-reporting ("backporting" it from the newer plugin API). However, that change accidentally forgot to invoke didResolveOperation from the request pipeline! This meant that the operation name never got reported. The change was backed out in #2557. But this unfortunately re-introduced the exact bug that the change in #2437 was intended to fix: operationName was no longer set when a result is served from the cache! Additionally, it was not set if a *plugin* didResolveOperation call threw, which is what happens when the operation registry plugin forbids an operation. While we could have fixed this by reintroducing the didResolveOperation extension API, there would be a subtle requirement that the apollo-engine-reporting extension didResolveOperation be run before the possibly-throwing operation registry didResolveOperation. So instead, @abernix implemented #2711. This used `requestContext.operationName` as a fallback if neither executionDidStart nor willResolveField gets called. This will be set if the operation properly parsed, validates, and either has a specified operationName that is found in the document, or there is no specified operationName and there is exactly one operation in the document and it has a name. (Note that no version of this code ever sent the user-provided operationName in case of parse or validation errors.) The existing code is correct, but this PR cleans up a few things: - #2557 reverted the one *implementation* of the didResolveOperation extension API, and #2437 accidentally didn't contain any *callers* of the API, but it was still declared on GraphQLExtension and GraphQLExtensionStack. This PR removes those declarations (which have never been useful). - We currently look for the operation name in willResolveField. But in any case where fields are successfully being resolved, the pipeline must have managed to successfully resolve the operation and set requestContext.operationName. So we don't actually need the willResolveField code, because the "fallback" in the requestDidStart end-callback will have the same value. So take this code away. (This change is the motivation for this PR; for federation metrics I'm trying to disengage the "calculate times for fields" part of trace generation from the rest of it.) - Fix the comment in "requestDidEnd" that implied incorrectly that requestContext.operationName was the user-provided name rather than the pipeline-calculated name. Be explicit both there and in requestPipeline.ts that we are relying on the fact that the RequestContext passed to requestDidStart is mutated to add operationName before its end handler is called. This change is intended to be a no-op change (other than the removal of the never-used APIs).
The full-query caching feature implemented in #2437 originally took the additional steps of changing the
apollo-engine-reporting
module to utilize the new request pipeline available in Apollo Server as of #1795. (See also #2441, #2441 (comment))While that would have been nice, there was still some uncertainty about some of the life-cycle hooks that would be necessary to make that happen and it wasn't worth blocking the implementation of full-query caching on those stalled decisions.
Therefore, the changes to utilize new functionality in the request pipeline, including what would have been a simplification of the way that
apollo-engine-reporting
would have obtained theoperationName
(something that is available via the API of the request-pipeline hooks), were backed out and will land separately in a future PR.The portion regarding
operationName
was inadvertently not backed out and instead was left leveraging a life-cycle hook which was not available to thegraphql-extensions
API:didResolveOperation
.This means that the code was not setting
operationName
in the way it needed to and thereforeoperationName
was always being left undefined (as is sometimes permitted!) with this newapollo-engine-reporting
.This commit puts the functionality back to that which is required for the
graphql-extensions
implementation, and the commit before this (8a43341) acts as a regression test (it should pass, as of this commit, and fail before it — see ❌ and ✅ on individual commits!).